﻿using System;
using System.IO;
using System.Net;
using System.Text;

namespace H.Sync.Http
{
    public class HttpClient
    {
        /// <summary>
        /// 发送数据的header数据
        /// </summary>
        public WebHeaderCollection Headers { get; set; }

        /// <summary>
        /// 发送请求时同时发送的Cookie数据
        /// </summary>
        public CookieContainer Cookie { get; set; }

        /// <summary>
        /// 用户标识
        /// </summary>
        public string UserAgent { get; set; } = "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:71.0) Gecko/20100101 Firefox/71.0";

        /// <summary>
        /// 编码类型
        /// </summary>
        public Encoding EncodingType { get; set; } = Encoding.UTF8;


        public HttpResult DoRequest(string url, byte[] data, string method, string contentType)
        {
            HttpResult httpResult = new HttpResult(EncodingType);
            HttpWebRequest request = null;

            try
            {
                request = WebRequest.Create(url) as HttpWebRequest;
                request.Method = method.ToString();
                if (Headers != null)
                {
                    request.Headers = Headers;
                }
                if (Cookie != null)
                {
                    request.CookieContainer = Cookie;
                }
                request.UserAgent = UserAgent;
                request.ServicePoint.Expect100Continue = false;

                if (data != null)
                {
                    request.ContentType = contentType;
                    request.ContentLength = data.Length;
                    request.AllowWriteStreamBuffering = true;
                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                        stream.Flush();
                    }
                }

                if (request.GetResponse() is HttpWebResponse webResponse)
                {
                    GetResponse(ref httpResult, webResponse);
                    webResponse.Close();
                }
            }
            catch (WebException err)
            {
                GetExceptionResponse(ref httpResult, err);
            }
            catch (Exception err)
            {
                GetExceptionResponse(ref httpResult, err);
            }
            finally
            {
                if (request != null)
                {
                    request.Abort();
                }
            }
            return httpResult;
        }

        /// <summary>
        /// HTTP GET方法请求数据
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        public HttpResult HttpGet(string url)
        {
            return DoRequest(url, null, "GET", null);
        }

        /// <summary>
        /// HTTP POST方法请求或发送数据
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public HttpResult HttpPost(string url, byte[] data, string contentType)
        {
            return DoRequest(url, data, "POST", contentType);
        }

        /// <summary>
        /// HTTP POST方法请求或发送数据
        /// </summary>
        /// <param name="url"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        public HttpResult HttpPost(string url, string data, string contentType)
        {
            return HttpPost(url, EncodingType.GetBytes(data), contentType);
        }


        /// <summary>
        /// 上传一个文件
        /// </summary>
        /// <param name="url"></param>
        /// <param name="key"></param>
        /// <param name="fileName"></param>
        /// <param name="data"></param>
        /// <param name="method"></param>
        /// <returns></returns>
        public HttpResult UploadFile(string url, string key, string fileName, byte[] data, string method = WebRequestMethods.Http.Post)
        {
            string spilter = "----WebKitFormBoundaryZpsWTsOiRHI0TBW7";
            string contentType = $"multipart/form-data; boundary={spilter}";
            byte[] spilterByte = EncodingType.GetBytes(spilter);
            using (MemoryStream ms = new MemoryStream())
            {
                ms.Write(spilterByte, 0, spilterByte.Length);

                byte[] input = EncodingType.GetBytes($"Content-Disposition: form-data; name=\"{key}\"; filename=\"{fileName}\"\r\nContent-Type: application/octet-stream\r\n\r\n");
                ms.Write(input, 0, input.Length);

                ms.Write(data, 0, data.Length);
                input = EncodingType.GetBytes("\r\n");
                ms.Write(input, 0, input.Length);
                ms.Write(spilterByte, 0, spilterByte.Length);

                return DoRequest(url, ms.ToArray(), method, contentType);
            }

        }

        /// <summary>
        /// 获取从服务器返回的内容
        /// </summary>
        /// <param name="result"></param>
        /// <param name="response"></param>
        private void GetResponse(ref HttpResult result, HttpWebResponse response)
        {
            try
            {
                result.StatusCode = response.StatusCode;
                using (MemoryStream ms = new MemoryStream()) using (Stream stream = response.GetResponseStream())
                {
                    stream.CopyTo(ms);
                    result.Content = ms.ToArray();
                }
            }
            catch (Exception err)
            {
                GetExceptionResponse(ref result, err);
            }
        }

        private void GetExceptionResponse(ref HttpResult result, WebException exception)
        {
            result.StatusCode = null;
            using (Stream stream = exception.Response.GetResponseStream())
            {

                byte[] bytes = new byte[stream.Length];
                stream.Read(bytes, 0, bytes.Length);
                result.Content = bytes;
            }
        }

        /// <summary>
        /// 从WebException中获取返回的内容
        /// </summary>
        private void GetExceptionResponse(ref HttpResult result, Exception exception)
        {
            result.StatusCode = null;
            result.Content = EncodingType.GetBytes(exception.Message);
        }
    }
}
